#include <pthread.h>
#include <functional>
#include <cstring>
#include <iostream>
// t.Start();
// t.Detach();
// sleep(5);

// t.Stop();
// sleep(5);
// t.Join();

namespace ThreadModlue
{
    //静态全局变量表示内部链接，使用uint32_t表示非负整数严格的32位保证可移植性
    //虽然这个可移植性前后矛盾了，因为使用了一个pthread_set/getname_np
    static uint32_t number = 1;
    class Thread
    {
        using func_t = std::function<void()>;
    private:
        void EnableRunning()
        {
            _isrunning = true;
        }
        
        static void* Routine(void* arg)
        {
            //使用static_cast的转换方式1.更加安全（它编译时会进行检查避免进行不相关类型的转换
            //2.更明确意图方便查找
            Thread* self = static_cast<Thread*>(arg);
            //先对标志位操作
            //为什么要封装_isrunning操作？不封装更本没法操作！
            self->EnableRunning();
            //初始化线程后直接设置分离（此时只有状态位被设置），启动线程后才设置分离（此时就直）
            //接能调用分离函数（系统调用顺序就是creat后启动线程然后才有ID，才能进行分离）
            //这里为了支持初始化后分离所以设置了检查
            if(self->_isdetach)
                self->Detach();//此时线程已经启动可以分离了
            //起个名字吧
            pthread_setname_np(self->_tid,self->_name.c_str());
            //回调
            self->_func();
            return nullptr;
        }
    public:
        Thread(func_t func)
            :_isrunning(false)
            ,_isdetach(false)
            ,_res(nullptr)
            ,_func(func)
            ,_tid(0)
        {
            _name = "thread-" + std::to_string(number++);
        }
        bool Start()
        {
            //为了避免重复启动，设置一个标记位
            if(_isrunning)
                return false;
            //线程库对线程操作要靠pthread_t tid（是一个虚拟地址），所以要把tid封装起来方便使用
            //这里为什么不直接使用外部提供的func呢？1.外部的函数参数不匹配
            //2.在线程类内部实现该函数可以对标记位（isrunning)进行设置,对线程名字设置
            //但是参数原因，Routine只能设置成static，然后由于设置成static就没有this指针，
            //所以要显式传递this指针
            int n = pthread_create(&_tid,nullptr,Routine,this);
            if(n != 0)
            {
                //pthread_creat返回值是一个错误码，所以可以使用strerror打印信息
                std::cerr << "pthread_create error:" << strerror(n) << std::endl;
                return false;
            }
            else{
                std::cout << _name << "creat success" << std::endl;
                return true;
            }
        }
        void Detach()
        {
            _isdetach = true;
            //1.初始化时设置了分离，如果此时start要调用分离？
            if(_isrunning)
            {
                pthread_detach(_tid);
            }
        }
        bool Stop()
        {
            //stop线程终止
            if(_isrunning)
            {
                //只有正在运行时才会处理
                int n = pthread_cancel(_tid);//可能会因为权限问题终止失败
                if(n != 0)
                {
                    std::cerr << "thread cancel error" << strerror(n) << std::endl;
                    return false;
                }
                else{
                    //成功
                    _isrunning = false;
                    std::cout << _name << "cancel success" << std::endl;
                    return true;
                }
            }
            return false;
        }
        void Join()
        {
            //线程等待
            //不能对一个已经分离了的线程进行等待
            if(_isdetach)
            {
                std::cout << "不能对分离线程等待" << std::endl;
                return;
            }
            //线程从它的线程函数中return或者被cancel就是终止了
            int n = pthread_join(_tid,&_res);//这里要不要把线程返回值也封装起来呢？
            if(n != 0)
            {
                std::cerr << "pthread_join error" << std::endl;
            }
            else{
                std::cout << "pthread_join success" << std::endl;
            }
        }
        ~Thread() {}
    private:
        //上层会传递下来的方法
        func_t _func;
        bool _isrunning;
        bool _isdetach;
        void * _res;
        pthread_t _tid;
        std::string _name;
    };
}